package logging

import (
	"archive/tar"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"

	"github.com/sirupsen/logrus"
	"gitee.com/Gakusyun/gakusyun-ws/utils"
)

// Archiver 日志归档器
type Archiver struct {
	logger *logrus.Logger
}

// NewArchiver 创建新的日志归档器
func NewArchiver(logger *logrus.Logger) *Archiver {
	return &Archiver{
		logger: logger,
	}
}

// StartDailyArchiving 启动每日日志归档
func (a *Archiver) StartDailyArchiving() {
	go func() {
		for {
			now := time.Now()
			nextMidnight := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, time.Local)
			time.Sleep(nextMidnight.Sub(now) + time.Second)

			if err := a.archiveDailyLog(now); err != nil {
				a.logger.Errorf("Failed to archive daily log: %v", err)
			}
		}
	}()
}

// StartMonthlyArchiving 启动每月日志归档
func (a *Archiver) StartMonthlyArchiving() {
	go func() {
		for {
			now := time.Now()
			nextFirstOfMonth := time.Date(now.Year(), now.Month()+1, 1, 0, 0, 0, 0, time.Local)
			time.Sleep(nextFirstOfMonth.Sub(now))

			if err := a.archiveMonthlyLogs(now); err != nil {
				a.logger.Errorf("Failed to archive monthly logs: %v", err)
			}
		}
	}()
}

// archiveDailyLog 归档每日日志
func (a *Archiver) archiveDailyLog(now time.Time) error {
	logFileName := ".gsws.log"
	logFilePath := filepath.Join(".", logFileName)
	archiveDir := "logs"

	if err := utils.CreateDirectory(archiveDir); err != nil {
		a.logger.Errorf("Failed to create logs directory: %v", err)
		return err
	}

	archiveFileName := now.Format("2006-01-02") + ".tar"
	archiveFilePath := filepath.Join(archiveDir, archiveFileName)

	return a.createTarArchive(archiveFilePath, logFilePath, logFileName)
}

// archiveMonthlyLogs 归档每月日志
func (a *Archiver) archiveMonthlyLogs(now time.Time) error {
	logsDir := "logs"
	monthlyArchivesDir := "monthly_archives"

	if err := utils.CreateDirectory(monthlyArchivesDir); err != nil {
		a.logger.Errorf("Failed to create monthly archives directory: %v", err)
		return err
	}

	archiveFileName := now.Format("2006-01") + ".tar.gz"
	archiveFilePath := filepath.Join(monthlyArchivesDir, archiveFileName)

	files, err := os.ReadDir(logsDir)
	if err != nil {
		a.logger.Errorf("Failed to read logs directory: %v", err)
		return err
	}

	// 创建压缩归档文件
	file, err := os.Create(archiveFilePath)
	if err != nil {
		a.logger.Errorf("Failed to create archive file: %v", err)
		return err
	}
	defer file.Close()

	gw := gzip.NewWriter(file)
	defer gw.Close()

	tw := tar.NewWriter(gw)
	defer tw.Close()

	for _, fileInfo := range files {
		if !fileInfo.IsDir() {
			logFilePath := filepath.Join(logsDir, fileInfo.Name())
			if err := a.addToTarArchive(tw, logFilePath, fileInfo.Name()); err != nil {
				a.logger.Errorf("Failed to add file to archive: %v", err)
				continue
			}

			// 删除已归档的文件
			if err := os.Remove(logFilePath); err != nil {
				a.logger.Errorf("Failed to remove log file: %v", err)
				continue
			}

			a.logger.Printf("Archived log file %s to %s", logFilePath, archiveFilePath)
		}
	}

	return nil
}

// createTarArchive 创建 tar 归档文件
func (a *Archiver) createTarArchive(archivePath, logPath, logName string) error {
	file, err := os.Create(archivePath)
	if err != nil {
		a.logger.Errorf("Failed to create archive file: %v", err)
		return err
	}
	defer file.Close()

	tw := tar.NewWriter(file)
	defer tw.Close()

	if err := a.addToTarArchive(tw, logPath, logName); err != nil {
		return err
	}

	// 清空日志文件
	if err := os.Truncate(logPath, 0); err != nil {
		a.logger.Errorf("Failed to truncate log file: %v", err)
		return err
	}

	a.logger.Printf("Archived log file to %s", archivePath)
	return nil
}

// addToTarArchive 将文件添加到 tar 归档中
func (a *Archiver) addToTarArchive(tw *tar.Writer, filePath, fileName string) error {
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		a.logger.Errorf("Failed to get file info: %v", err)
		return fmt.Errorf("failed to get file info: %w", err)
	}

	header, err := tar.FileInfoHeader(fileInfo, fileName)
	if err != nil {
		a.logger.Errorf("Failed to create tar header: %v", err)
		return fmt.Errorf("failed to create tar header: %w", err)
	}

	header.Name = fileName

	if err := tw.WriteHeader(header); err != nil {
		a.logger.Errorf("Failed to write tar header: %v", err)
		return fmt.Errorf("failed to write tar header: %w", err)
	}

	file, err := os.Open(filePath)
	if err != nil {
		a.logger.Errorf("Failed to open file: %v", err)
		return fmt.Errorf("failed to open file: %w", err)
	}
	defer file.Close()

	if _, err := io.Copy(tw, file); err != nil {
		a.logger.Errorf("Failed to copy file to tar: %v", err)
		return fmt.Errorf("failed to copy file to tar: %w", err)
	}

	return nil
}